﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Threading;
using System.Drawing;
using SSM.SmartMosaicUtils.Net;
using SSM.DeepZoomViewer.Utils;

namespace SSM.DeepZoomViewer
{
    public enum LoadState
    {
        Loaded,
        Loading,
        UnLoaded
    }

    /// <summary>
    /// 각 타일을 나타내는 클래스
    /// </summary>
    public class Tile
    {
        public string SessionId { get; private set; }

        public int Level { get; private set; }

        public int HorizontalIndex { get; private set; }

        public int VerticalIndex { get; private set; }

        public event EventHandler LoadCompleted;

        public LoadState LoadState { get; private set; }

        private string deepZoomUrl;

        private Thread currentThread;

        private Bitmap imageBitmap;

        /// <summary>
        /// 생성자
        /// </summary>
        /// <param name="level"></param>
        /// <param name="horizontalIndex"></param>
        /// <param name="verticalIndex"></param>
        public Tile(string sessionId, int level, int horizontalIndex, int verticalIndex, string deepZoomUrl)
        {
            this.deepZoomUrl = deepZoomUrl;
            SessionId = sessionId;
            Level = level;
            HorizontalIndex = horizontalIndex;
            VerticalIndex = verticalIndex;

            LoadState = LoadState.UnLoaded;
        }

        /// <summary>
        /// 이미지를 바로 리턴합니다.
        /// </summary>
        public Bitmap LoadImage()
        {
            return imageBitmap;
        }

        /// <summary>
        /// 로드 요청
        /// </summary>
        public void LoadRequest()
        {
            if (LoadState == LoadState.UnLoaded)
            {
                // 상태를 로딩으로 변환시킨다.
                LoadState = LoadState.Loading;

                string key = HorizontalIndex + "," + VerticalIndex;

                string tileDirectory = DeepZoomViewerConstants.TMP_PATH + "\\" + SessionId + "\\" + Level;

                string tilePath =
                    tileDirectory + "\\" + HorizontalIndex + "_" + VerticalIndex + ".jpg";

                // 파일이 존재하지 않으면 다운로드 합니다.
                if (!File.Exists(tilePath))
                {
                    // 다운로드 시작
                    currentThread = new Thread(ImageLoadFromServer);
                    currentThread.Priority = ThreadPriority.BelowNormal;
                    currentThread.Start();
                }
                // 파일이 존재하는 경우
                else
                {
                    // 파일에서 읽어오기 시작
                    currentThread = new Thread(ImageLoadFromFile);
                    currentThread.Priority = ThreadPriority.BelowNormal;
                    currentThread.Start();
                }
            }
        }

        private void ImageLoadFromServer()
        {
            FileDownloader fileDownloader = new FileDownloader();

            string key = HorizontalIndex + "," + VerticalIndex;

            string tileDirectory = DeepZoomViewerConstants.TMP_PATH + "\\" + SessionId + "\\" + Level;

            string tilePath =
                tileDirectory + "\\" + HorizontalIndex + "_" + VerticalIndex + ".jpg";

            try
            {
                // 디렉토리가 없으면 디렉토리를 생성합니다.
                if (!Directory.Exists(tileDirectory))
                    Directory.CreateDirectory(tileDirectory);

                fileDownloader.DownloadFile(
                    deepZoomUrl
                    + DeepZoomViewerConstants.DEEPZOOM_IMAGE_SUB_URL
                    + Level + "/" + HorizontalIndex + "_" + VerticalIndex + ".jpg",
                    tilePath
                    );

                imageBitmap = new Bitmap(tilePath);

                OnLoad();
            }
            catch (DirectoryNotFoundException ex)
            {
                LoadState = LoadState.UnLoaded;
            }
            catch (ThreadAbortException ex)
            {
                LoadState = LoadState.UnLoaded;

                if (imageBitmap != null)
                {
                    imageBitmap.Dispose();
                    imageBitmap = null;
                }

                // 억지로 중지할때 발생하는 예외
                // 파일 다운로드 닫기
                fileDownloader.CancelDownloadFile();
            }
        }

        private void ImageLoadFromFile()
        {   
            string key = HorizontalIndex + "," + VerticalIndex;

            string tileDirectory = DeepZoomViewerConstants.TMP_PATH + "\\" + SessionId + "\\" + Level;

            string tilePath =
                tileDirectory + "\\" + HorizontalIndex + "_" + VerticalIndex + ".jpg";

            try
            {
                imageBitmap = new Bitmap(tilePath);

                OnLoad();
            }
            catch (FileNotFoundException ex)
            {
                this.LoadState = LoadState.UnLoaded;
            }
            catch (IOException ex)
            {
            }
            catch (ArgumentException ex)
            {
                this.LoadState = LoadState.UnLoaded;

                File.Delete(tilePath);
            }
            catch (ThreadAbortException ex)
            {
                // 억지로 중지할때 발생하는 예외
                LoadState = LoadState.UnLoaded;

                if (imageBitmap != null)
                {
                    imageBitmap.Dispose();
                    imageBitmap = null;
                }
            }
        }

        private void OnLoad()
        {
            LoadState = LoadState.Loaded;

            // 로드가 완료됨을 알린다.
            if (LoadCompleted != null)
            {
                LoadCompleted(this, null);
            }
        }

        /// <summary>
        /// 로드 취소
        /// </summary>
        public void CancelLoadRequest()
        {
            if (LoadState == LoadState.Loading)
            {
                string key = HorizontalIndex + "," + VerticalIndex;

                string tileDirectory = DeepZoomViewerConstants.TMP_PATH + "\\" + SessionId + "\\" + Level;

                string tilePath =
                    tileDirectory + "\\" + HorizontalIndex + "_" + VerticalIndex + ".jpg";

                currentThread.Abort();
            }
            else if (LoadState == LoadState.Loaded)
            {
                if (imageBitmap != null)
                    imageBitmap.Dispose();
            }

            LoadState = LoadState.UnLoaded;
        }
    }
}
